import os
import math
import time

from PyQt4 import QtGui, QtCore

from shuffler import Shuffler

from gamecontrols import *
from imagemanipulation import *

import cv

class ImagePixmapItem(QtGui.QGraphicsPixmapItem):
    def __init__(self, pmap):
        QtGui.QGraphicsPixmapItem.__init__(self, pmap)
        self.src_pmap = pmap
        self.old_pmap = pmap
        self.selected = False
        
    def mousePressEvent(self, event):
        try:
            if self.source != None:
                self.source.selectTile(self.uid)
        except Exception:
            pass
        
    def setSelected(self, bool):   
        if bool:
            if self.selected == False:
                ## Draw rectangle around edge of pixmap
                self.selected = True
                self.old_pmap = self.pixmap()
                self.new_pmap = drawBorder(self.old_pmap, 'yellow')
                self.setPixmap(self.new_pmap)
        else:
            self.setPixmap(self.old_pmap)
            self.selected = False
        
class UnshufflerGameFrame(QtGui.QWidget):
    def __init__(self, parent = None):
        QtGui.QWidget.__init__(self, None)
        self.parent = parent
        self.w,self.h = parent.settings.im_width, parent.settings.im_height
        
        self.controls = GameControls(self)
    
        self.selections = []
        self.selection_box = None
        self.in_play = False
        self.first_load = True
 
        ## Create graphicsview and scene
        self.gview = QtGui.QGraphicsView(self)
        self.scene = QtGui.QGraphicsScene(self)
        self.gview.setScene(self.scene)
        self.gview.setStyleSheet("QGraphicsView { border: 1px solid rgb(185,185,185); \
                                                  border-radius: 3px; }")
        
        ## Create background gradient
        rad = QtGui.QRadialGradient(450, 350, 2000)
        rad.setColorAt(0, QtGui.QColor(125,125,125))
        rad.setColorAt(1, QtGui.QColor(250,250,255))
        rad.setSpread(QtGui.QGradient.RepeatSpread)
        self.scene.setBackgroundBrush(rad)
        
        ## Create layout
        hbox = QtGui.QHBoxLayout(self)
        hbox.addWidget(self.gview)
        hbox.addWidget(self.controls)
        self.setLayout(hbox)
        hbox.setContentsMargins(0,0,0,0)
        hbox.setSpacing(0)
        
        self.gview.show()

    def addChunk(self, h, v):
        i = len(self.chunks) 
        self.chunks.append(Chunk(h,v,i))
        
    def countDown(self):
        if self.i == 0:
            self.countdown_timer.stop()
            self.scene.removeItem(self.overlay)
            self.startGame()
            self.refresh()
        else:
            if self.overlay:
                self.scene.removeItem(self.overlay)
                self.overlay = ImagePixmapItem(mk_countDown(self.parent.settings.im_width,
                                                                self.parent.settings.im_height, self.i))
                self.scene.addItem(self.overlay)
                self.refresh()
                self.i -= 1
        
    def doCountDown(self):
        self.i = 3
        self.countdown_timer = QtCore.QTimer(self)
        self.connect(self.countdown_timer, QtCore.SIGNAL('timeout()'), self.countDown)
        self.countdown_timer.start(1000)
        
    def drawWinOverlay(self):
        self.overlay = ImagePixmapItem(mk_win(self.parent.settings.im_width,
                                                            self.parent.settings.im_height))
        self.scene.addItem(self.overlay)
        
    def drawLoseOverlay(self):
        self.overlay = ImagePixmapItem(mk_lose(self.parent.settings.im_width,
                                                            self.parent.settings.im_height))
        self.scene.addItem(self.overlay)
        
    def initGame(self, image = None, overlay = False):

        self.scene.clear()
        
        if image != None: self.image = image
        
        ## Load, break up, and shuffle an image
        shuffler = Shuffler(self)
        self.win_order, shuffled = shuffler.shuffleImage(self.image,
                                                        self.parent.settings.cuts,
                                                        self.parent.settings.im_width,
                                                        self.parent.settings.im_height)
        
        ## Create labels and pixmaps for the images
        imgs  = [QtGui.QLabel(self) for i in shuffled]
        pmaps = [QtGui.QPixmap().fromImage(mat_to_qimage(img)) for img in shuffled]
        
        self.pmaps = [ImagePixmapItem(pmap) for pmap in pmaps]

        ## Locations to draw images
        locs = [(x,y)
                for y in range(0, self.h-self.h/(int(math.sqrt(len(self.pmaps))))+1, self.h/int(math.sqrt(len(self.pmaps))))
                for x in range(0, self.w-self.w/(int(math.sqrt(len(self.pmaps))))+1, self.w/int(math.sqrt(len(self.pmaps))))]

        ## Store useful info in pmap objects
        for i,pmap in enumerate(self.pmaps): 
            pmap.source = self
            pmap.uid = i
            pmap.setPos(QtCore.QPointF(locs[i][0],locs[i][1]))
       
        ## Add subrects to scene
        [self.scene.addItem(pmap) for pmap in self.pmaps]
        
        ## Add overlay that says "press start"
        if overlay:
            self.overlay = ImagePixmapItem(mk_pressStartPmap(self.parent.settings.im_width,
                                                             self.parent.settings.im_height))
            self.scene.addItem(self.overlay)

        ## Create background gradient
        rad = QtGui.QRadialGradient(self.w, self.h, 2000)
        rad.setColorAt(0, QtGui.QColor(125,125,125))
        rad.setColorAt(1, QtGui.QColor(255,255,255))
        rad.setSpread(QtGui.QGradient.RepeatSpread)
        self.scene.setBackgroundBrush(rad)
        self.refresh()

    def refresh(self):
        self.gview.update()

    def selectTile(self, uid):

        # Don't allow more thani two selections, and BTW something should have happened by now
        assert len(self.selections) < 2

        selected_pmap = [p for p in self.pmaps if p.uid == uid][0]

        ## Clicked the same tile twice
        if uid in self.selections:
            selected_pmap.setSelected(False)
            self.selections = []
            return

        self.selections.append(uid)

        ## First selection
        if len(self.selections) == 1:
            selected_pmap.setSelected(True)
        
        ## Second selection: initiate swap, and check if the game has been won
        elif len(self.selections) == 2:
            
            [p.setSelected(False) for p in self.pmaps]
            
            # Swap the tiles
            s = self.selections
            self.swapTile(s[0], s[1])
            self.selections = []
            
            ## Check if we've won
            if self.in_play:
                curr_order = [p.uid for p in self.pmaps]
                if curr_order == self.win_order: self.winGame()
        
        self.refresh()

    def swapTile(self, first_uid, second_uid):
        
        ## Find tiles
        f1 = lambda x: x.uid == first_uid        
        f2 = lambda x: x.uid == second_uid        
        tile1 = filter(f1, self.pmaps)[0]
        tile2 = filter(f2, self.pmaps)[0]
        
        ## Swap positions, ids
        pos1 = tile1.pos()
        pos2 = tile2.pos()
        tile1.setPos(pos2)
        tile2.setPos(pos1)
        tile2.uid = first_uid
        tile1.uid = second_uid
        
        self.refresh()

    def startGame(self):
        print 'Starting the game...'
        self.initGame(overlay=False)
        self.parent.status_bar.showMessage('Starting the game... Good luck!', 3500)
        self.controls.timer.reset()
        self.controls.timer.startTime()
        self.in_play = True
    
    def stopGame(self):
        print 'Stopping the game...'
        self.parent.status_bar.showMessage('Sit down, give your mind a rest - it obviously needs it.', 3500)
        self.drawLoseOverlay()
        self.controls.timer.stopTime()
        self.controls.timer.reset()
        self.in_play = False

    def winGame(self):
        print 'The player won the game...'
        self.parent.status_bar.showMessage('You Win!', 5000)
        self.drawWinOverlay()
        self.controls.timer.stopTime()
        self.controls.timer.reset()
        self.in_play = False